/*****************************************************************************
******************************************************************************

bmpdiff

Author: Gordon McCreight
email: gordon@mccreight.com

date modified: 2008-05-13
      version: 0.05

  License: GPL 2
Copyright: 2008 by Gordon McCreight

usage: bmpdiff tolerance_r tolerance_g tolerance_b image_a.bmp image_b.bmp
tolerances are 0-255

description:
  Compare two isometric BMP files and print a
  list of pixel positions where they differ.
  Prints a comma seperated list of x,y (for
  one match) or x,y,x,y,x,y for
  multiple matches.

Note: can be compiled in like so:
g++ -o bmpdiff bmpdiff.cpp EasyBMP.cpp

After you compile, you might want to test with this:
./bmpdiff 0 0 0 test_images/first.bmp test_images/second.bmp

******************************************************************************
*****************************************************************************/

#include <stdlib.h>
#include "EasyBMP.h"

//#define DEBUG

using namespace std;

//[tag:performance:gem] Not sure if the "static inline" does any good.
static inline double Abs (double Nbr) {
    if( Nbr >= 0 )
        return Nbr;
    else
        return -Nbr;
}

int main( int argc, char* argv[] ) {

    int optind = 1;
    int has_written_results = 0;

    int tolerance_r = atoi(argv[ optind ]);
    optind++;

    int tolerance_g = atoi(argv[ optind ]);
    optind++;

    int tolerance_b = atoi(argv[ optind ]);
    optind++;

    int has_tolerance_bool = 0;
    if (tolerance_r > 0 || tolerance_g > 0 || tolerance_b > 0) {
        has_tolerance_bool = 1;
    }

#ifdef DEBUG
    fprintf( stderr, "Loading first BMP image '%s'\n", argv[optind] );
#endif
    BMP ImageA;
    ImageA.ReadFromFile(argv[ optind ]);
    optind++;

#ifdef DEBUG
    fprintf( stderr, "Loading second BMP image '%s'\n", argv[optind] );
#endif
    BMP ImageB;
    ImageB.ReadFromFile(argv[ optind ]);
    optind++;

    int first_height = ImageA.TellHeight();
    int first_width = ImageA.TellWidth();

    if( first_width != ImageB.TellWidth() || first_height != ImageB.TellHeight() ) {
        fprintf( stderr, "The heights or widths do not match\n" );
        exit(2);
    }

    for (int bmp_y = 0; bmp_y < first_height; ++bmp_y) {
        for (int bmp_x = 0; bmp_x < first_width; ++bmp_x) {

            int all_channels_matched = 1;

            RGBApixel* PixelA = ImageA(bmp_x, bmp_y);
            RGBApixel* PixelB = ImageB(bmp_x, bmp_y);

            if ( has_tolerance_bool == 0 ) {
                // zero tolerance, so do it faster
                if ( PixelA->Red != PixelB->Red ) {
                    all_channels_matched = 0;
                }
                else if ( PixelA->Green != PixelB->Green ) {
                    all_channels_matched = 0;
                }
                else if ( PixelA->Blue != PixelB->Blue ) {
                    all_channels_matched = 0;
                }
            }
            else {
                if ( Abs(PixelA->Red - PixelB->Red) > tolerance_r ) {
                    all_channels_matched = 0;
                }
                else if ( Abs(PixelA->Green - PixelB->Green) > tolerance_g ) {
                    all_channels_matched = 0;
                }
                else if ( Abs(PixelA->Blue - PixelB->Blue) > tolerance_b ) {
                    all_channels_matched = 0;
                }
            }

            if (! all_channels_matched) {
                if (has_written_results == 1) {
                    cout << ",";
                }
                cout << bmp_x << "," << bmp_y;
                has_written_results = 1;
            }

        }
    }
    
    if (has_written_results == 1) {
        cout << endl;
    }
    
    return 0;

}
